/** @type {HTMLCanvasElement} */
const canvas = document.getElementById("canvas")

const ctx = canvas.getContext("2d")
let startMove = false;
const points = []

const drawAxis = (ctx, config) => {
  ctx.save()
  const {
    origin,
    xAxis,
    yAxis
  } = config
  ctx.lineWidth = 1
  ctx.strokeStyle = "orange"
  ctx.beginPath()
  const xAxisHeight = 5
  const {
    gap
  } = xAxis


  ctx.moveTo(origin.x, origin.y)
  ctx.lineTo(origin.x + xAxis.length, origin.y)
  for (let i = 1; i < xAxis.length / gap; i++) {
    ctx.moveTo(origin.x + gap * i, origin.y)
    ctx.lineTo(origin.x + gap * i, origin.y - xAxisHeight)
  }

  ctx.moveTo(origin.x, origin.y)
  ctx.lineTo(origin.x, origin.y - yAxis.length)
  for (let i = 1; i < yAxis.length / gap; i++) {
    ctx.moveTo(origin.x, origin.y - gap * i)
    ctx.lineTo(origin.x + xAxisHeight, origin.y - gap * i)
  }


  ctx.stroke()
  ctx.closePath();
  ctx.restore()
}

const drawPoint = (ctx, cx, cy, r) => {
  ctx.save();
  ctx.lineWidth = 1
  ctx.moveTo(cx, cy)
  ctx.beginPath()
  ctx.arc(cx, cy, r, 0, Math.PI * 2)
  ctx.fillStyle = "#fff"
  ctx.fill()
  ctx.strokeStyle = "blue"
  ctx.stroke()
  ctx.closePath()
  ctx.restore()
}

const drawPoints = (ctx, points) => {
  points.forEach(p => {
    drawPoint(ctx, p.x, p.y, p.r)
  })
}

const drawLine = (ctx, p1, p2) => {
  ctx.save();
  ctx.beginPath();
  ctx.moveTo(p1.x, p1.y)
  ctx.lineTo(p2.x, p2.y)
  ctx.stroke();
  ctx.closePath();
  ctx.restore();
}
const drawLines = (ctx, points) => {
  if (points.length < 1) {
    return
  }
  ctx.save();
  ctx.beginPath();
  ctx.moveTo(points[0].x, points[0].y)
  for (let i = 1; i < points.length; i++) {
    ctx.lineTo(points[i].x, points[i].y)
  }
  ctx.stroke();
  ctx.closePath();
  ctx.restore();
}

const drawSmoothLines = (ctx, points) => {
  if (points.length < 3) {
    drawLines(ctx, points)
    return
  }
  const f = 0.4
  const t = 0.6
  const gradient = (a, b) => (b.y - a.y) / (b.x - a.x)
  ctx.save()

  ctx.beginPath()
  ctx.moveTo(points[0].x, points[0].y)
  let g = 0
  let dx1 = 0
  let dy1 = 0
  let dx2 = 0
  let dy2 = 0
  let prePoint = points[0]
  let nextPoint = null
  for (let i = 1; i < points.length; i++) {
    let curPoint = points[i]
    nextPoint = points[i + 1]
    if (nextPoint) {
      g = gradient(prePoint, nextPoint)
      dx2 = (nextPoint.x - curPoint.x) * (-f)
      dy = dx2 * g * t
    } else {
      dx2 = 0
      dy2 = 0
    }
    ctx.bezierCurveTo(prePoint.x - dx1, prePoint.y - dy1, curPoint.x + dx2, curPoint.y + dy2, curPoint.x, curPoint.y)
    dx1 = dx2
    dy1 = dy2
    prePoint = curPoint
  }
  ctx.stroke()
  ctx.closePath()

  ctx.restore()
}

const canvasInit = () => {
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  drawAxis(ctx, {
    origin: {
      x: 1,
      y: 220
    },
    xAxis: {
      length: 400,
      gap: 10
    },
    yAxis: {
      length: 300,
      gap: 10
    }
  })
  drawSmoothLines(ctx, points)
  drawPoints(ctx, points)
}
canvasInit();

canvas.addEventListener("click", e => {
  const clickPosition = {
    x: e.clientX,
    y: e.clientY
  }
  const {
    left,
    top
  } = canvas.getBoundingClientRect()
  const canvasOffset = {
    x: left,
    y: top
  }

  points.push({
    x: clickPosition.x - canvasOffset.x,
    y: clickPosition.y - canvasOffset.y,
    r: 5
  })
  canvasInit()
})

canvas.addEventListener("mousemove", e => {
  const inCircle = (p, cx, cy, r) => {
    const distance = Math.sqrt((p.x - cx) ** 2 + (p.y - cy) ** 2)
    if (distance <= r) {
      return true
    }
    return false
  }
  const mousePosition = {
    x: e.clientX,
    y: e.clientY
  }
  const {
    left,
    top
  } = canvas.getBoundingClientRect()
  const canvasOffset = {
    x: left,
    y: top
  }
  const canvasPosition = {
    x: mousePosition.x - canvasOffset.x,
    y: mousePosition.y - canvasOffset.y
  }
  let repaintFlag = false
  for (let i = 0; i < points.length; i++) {
    const ifInCircle = inCircle(canvasPosition, points[i].x, points[i].y, points[i].r)
    if (ifInCircle && points[i].r == 5) {
      points[i].r = 8
      repaintFlag = true
      canvas.style.cursor = "pointer"
      break;
    } else if (!ifInCircle && points[i].r !== 5) {
      points[i].r = 5
      repaintFlag = true
      canvas.style.cursor = ""
      break
    }
  }
  if (repaintFlag) {
    canvasInit();
  }
})